﻿using MySql.Data.MySqlClient;
using System.Diagnostics;

namespace RBAC.Read.Api.MYSQL
{
    public class MySqlBackupService : IDatabaseBackupService
    {
        private readonly string _connectionString;
        private readonly string _mysqlDumpPath;
        private readonly string _mysqlPath;
        private readonly ILogger<MySqlBackupService> _logger;

        public MySqlBackupService(string connectionString, string mysqlDumpPath = "mysqldump", string mysqlPath = "mysql", ILogger<MySqlBackupService> logger = null)
        {
            _connectionString = connectionString;
            _mysqlDumpPath = mysqlDumpPath;
            _mysqlPath = mysqlPath;
            _logger = logger;
        }
        public async Task<bool> BackupDatabaseAsync(string backupPath, CancellationToken cancellationToken = default)
        {
            try
            {
                var builder = new MySqlConnectionStringBuilder(_connectionString);
                var databaseName = builder.Database;
                var arguments = $"--host={builder.Server} --port={builder.Port} --user={builder.UserID} --password={builder.Password} --single-transaction --routines --triggers {databaseName}";

                var startInfo = new ProcessStartInfo
                {
                    FileName = _mysqlDumpPath,
                    Arguments = arguments,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };

                using var process = new Process { StartInfo = startInfo };
                process.Start();

                using var fileStream = new FileStream(backupPath, FileMode.Create, FileAccess.Write);
                using var writer = new StreamWriter(fileStream);

                await process.StandardOutput.BaseStream.CopyToAsync(fileStream, cancellationToken);
                await process.WaitForExitAsync(cancellationToken);

                if (process.ExitCode != 0)
                {
                    var error = await process.StandardError.ReadToEndAsync();
                    _logger?.LogError($"备份失败: {error}");
                    return false;
                }

                _logger?.LogInformation($"数据库 {databaseName} 备份成功，保存至 {backupPath}");
                return true;
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "备份数据库时发生错误");
                return false;
            }
        }

        public async Task<bool> RestoreDatabaseAsync(string backupPath, CancellationToken cancellationToken = default)
        {
            try
            {
                if (!File.Exists(backupPath))
                {
                    _logger?.LogError($"备份文件不存在: {backupPath}");
                    return false;
                }

                var builder = new MySqlConnectionStringBuilder(_connectionString);
                var databaseName = builder.Database;
                var arguments = $"--host={builder.Server} --port={builder.Port} --user={builder.UserID} --password={builder.Password} {databaseName}";

                var startInfo = new ProcessStartInfo
                {
                    FileName = _mysqlPath,
                    Arguments = arguments,
                    RedirectStandardInput = true,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };

                using var process = new Process { StartInfo = startInfo };
                process.Start();

                using var fileStream = new FileStream(backupPath, FileMode.Open, FileAccess.Read);
                await fileStream.CopyToAsync(process.StandardInput.BaseStream, cancellationToken);
                process.StandardInput.Close();

                await process.WaitForExitAsync(cancellationToken);

                if (process.ExitCode != 0)
                {
                    var error = await process.StandardError.ReadToEndAsync();
                    _logger?.LogError($"恢复失败: {error}");
                    return false;
                }

                _logger?.LogInformation($"数据库 {databaseName} 从 {backupPath} 恢复成功");
                return true;
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "恢复数据库时发生错误");
                return false;
            }
        }

        public async Task<IEnumerable<string>> ListBackupsAsync(string backupDirectory)
        {
            var backups = new List<string>();

            if (Directory.Exists(backupDirectory))
            {
                var files = Directory.GetFiles(backupDirectory, "*.sql")
                                    .OrderByDescending(f => new FileInfo(f).CreationTime);
                backups.AddRange(files);
            }

            return await Task.FromResult(backups);
        }
    }
}
